home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: MegaDisc / MegaDisc 36 (1993-11)(MegaDisc Digital Publishing)(AU)(Disk 2 of 2).zip / MegaDisc 36 (1993-11)(MegaDisc Digital Publishing)(AU)(Disk 2 of 2).adf / ARexx / Chars / Chars_Doc / Chars_Doc
Text File  |  1993-10-20  |  15KB  |  334 lines

  1.   
  2.                                              
  3.              ARexx : Designing Individual    
  4.              Characters for Special Needs     by John Collett
  5.                                              
  6.  
  7.  
  8.     36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36  
  9.  
  10.        
  11.       Introduction  
  12.     
  13.     An old and much-maligned BBC computer languishes in my basement, unused
  14.     since the day I got my Amiga.  When I bought the BBC, what seems like a
  15.     lifetime ago, it was a serious contender in the field, and I never
  16.     regretted the purchase.  Even now, I grudgingly concede, it had some
  17.     pretty nifty features.  For example, I could easily, at any time,
  18.     design any new character I needed, assign it to an ASCII value in a
  19.     specified range above 128, and then use it by referring to it by its
  20.     ASCII value.  The following is an account of an attempt to obtain a
  21.     similar facility on an Amiga.
  22.     
  23.       Two programs and a data file  
  24.     
  25.     The exercise involved the writing of two ARexx programs which I have
  26.     called 'CharGrid' and 'CharsDemo'.  The main component of the first,
  27.     as its name implies, is a grid of 8 * 8 cells which represent the
  28.     lines and pixels of a character.  Each cell can be switched to 'on' -
  29.     shaded in - by a mouse click, or equally easily switched off. 
  30.  
  31.     The second program as it stands simply displays a few examples, but its
  32.     main functions could readily be used in any other program in which
  33.     special characters are needed.  Communication between 'CharGrid' and
  34.     any subsequent application using the 'CharsDemo' functions is via a
  35.     character storage file.  The small sample file here called 'chars'
  36.     holds definitions for 20 or so characters, but there is virtually no
  37.     limit to its possible size, and no restrictions on its name.
  38.     
  39.     If you run 'CharsDemo' (which it might be a good idea to do first,
  40.     before you try defining characters of your own), you will see that it
  41.     is anything but blindingly fast in its operation.  A 'Rexx Plus'
  42.     compiled version is noticeably faster, though still not as fast as I
  43.     would like it to be, probably because I never have what you
  44.     could call a smooth run when compiling with 'Rexx Plus'.  I've still
  45.     got a lot of learning to do there.
  46.  
  47.     
  48.         How 'CharsDemo' and 'CharGrid' work  
  49.    
  50.     The major tasks of 'CharGrid' are to enable a user to design a
  51.     character, and then to store labels and numbers in a file.
  52.     
  53.     To make it easy to adjust pixels at the design stage, a grid is used
  54.     to represent a character at 8 times its normal size.
  55.  
  56.         ·······*   1    An 'on' pixel is here shown as '*'.   
  57.         ······*·   2    A value can be given to each pixel in    
  58.         ·····*··   4    a row, expressed as 2 to the power of
  59.         ····*···   8    the column number, counting columns
  60.         ···*····  16    from the right, 0 to 7.  The numbers   
  61.         ··*·····  32    shown here range from 1 ( = 2**0) to      
  62.         ·*······  64    128 ( = 2**7).                               
  63.         *······· 128    '**' is the ARexx exponentiation symbol. 
  64.                                    
  65.         ·······*   1     If more than one pixel in a row is 'on',
  66.         ······**   3     their values can be summed. In the 
  67.         ·····***   7     second row, 1 + 2 = 3, and so on.
  68.         ····****  15     Any number between 1 and 255 can
  69.         ···*****  31     uniquely define the state of all the
  70.         ··******  63     pixels in a given row.
  71.         ·******* 127   
  72.         ******** 255   
  73.  
  74.         ···**···  24     A character '1' which differs from the
  75.         ··***···  56     standard could be defined as shown
  76.         ·****··· 120     here.  The set of numbers, 24 to 126,
  77.         ···**···  24     can be stored and used later to
  78.         ···**···  24     recreate the character as displayed.
  79.         ···**···  24    
  80.         ···**···  24   
  81.         ·******· 126   
  82.     
  83.     The three sample shapes we have just looked at could be stored thus,
  84.     with a label for the purposes of identification, and eight numeric
  85.     values in each case :
  86.  
  87.         diag,1,2,4,8,16,32,64,128
  88.         triang,1,3,7,15,31,63,127,255
  89.         one,24,56,120,24,24,24,24,126
  90.     
  91.     The tasks of the main functions in 'CharsDemo' are to lift required
  92.     sets of data out of the file and, line by line, to draw up characters
  93.     according to the stored pixel values. 
  94.  
  95.     
  96.          A closer look at 'CharGrid'  
  97.     
  98.     In a 'rexxarplib' window opened for the purpose, a grid and a column
  99.     of gadgets ('Show' to 'Quit') are displayed :
  100.  
  101.            _______________    
  102.           |_|_|_|_|_|_|_|_|   0   Show  -->
  103.           |_|_|_|_|_|_|_|_|   0   Save
  104.           |_|_|_|_|_|_|_|_|   0   Clear
  105.           |_|_|_|_|_|_|_|_|   0   Load
  106.           |_|_|_|_|_|_|_|_|   0   Help
  107.           |_|_|_|_|_|_|_|_|   0   Quit
  108.           |_|_|_|_|_|_|_|_|   0
  109.           |_|_|_|_|_|_|_|_|   0  
  110.     
  111.  
  112.     A mouse click within the grid toggles a cell on/off, and the
  113.     character shape is built up as you make successive 'on' clicks.  The
  114.     column of row totals, here shown as zeros, is constantly updated,
  115.     just to provide visual confirmation of what's going on. (No value is
  116.     shown for any row until one of its cells has been activated.)
  117.  
  118.     If at any time you want to see what your new character is going to
  119.     look like when used, click on 'Show', and it will appear next to the
  120.     '-->', at its real size, one-eighth of that of the grid.  The process
  121.     is similar to that used by the 'CharsDemo' program when user-defined
  122.     characters are actually used.  It is a bit complicated, and takes a
  123.     second or two to do its job.  We'll have a closer look at one or
  124.     two of the details later on.
  125.  
  126.     When you want to save a character, click on 'Save'.  When you want to
  127.     edit a previously saved character, click on 'Load'.  If this is the
  128.     first 'Save' or 'Load' in the current session, a file requester will
  129.     appear asking you to specify a file name.  For saving, this will be
  130.     either an existing file to which new characters may be appended, or
  131.     the name of a new file which you wish to create.  For loading, it
  132.     must, of course, be an existing file.  Once the file is open (or 
  133.     straightaway if it has been opened earlier), you are asked to provide a
  134.     label for the character which you wish to save or load.  In 'Load',
  135.     assuming the data for the requested character exists, the relevant
  136.     cells of the grids are shaded in one after the other, and you can then
  137.     edit the design if you wish.
  138.  
  139.     'Clear' clears the grid, 'Help' provides a list of brief reminders,
  140.     and 'Quit' exits the program.
  141.  
  142.     Have a look at my file 'chars' to see the format of the entries I have
  143.     saved.
  144.  
  145.     
  146.       A closer look at 'CharsDemo'  
  147.     
  148.     For ages I have been using in ARexx a print-at function which takes
  149.     a piece of text and prints it at given x and y values.
  150.     
  151.     That was the beginning of a much more complicated function in
  152.     'CharsDemo' which I have called 'Chart'.  It first examines the text
  153.     which it is to print for the presence of any label markers { and }. 
  154.     Between the braces is a character label, and when any labels in a line
  155.     of text have been located in the relevant file, the data required to
  156.     draw the character(s) in question is obtained from the same source.
  157.  
  158.     Any unmarked text, not in braces, is printed in the usual way, and
  159.     then the required special characters are constructed at the indicated
  160.     position.  For example, if we had defined as BigJ and BigK two
  161.     characters which looked something like a J and a K, then 
  162.  
  163.           call Chart(30,40,'Here is {BigJ} and here is {BigK}.')
  164.     
  165.     would produce something like the following at position 30,40 :
  166.     
  167.           Here is J and here is K.
  168.     
  169.     'CharsDemo' simply gives a few examples,  which include alpha, beta,
  170.     pi, chi, a couple of symbols from the International Phonetic Alphabet,
  171.     and a demo of how adjacent shapes can be made to look like a single
  172.     large character.
  173.  
  174.     
  175.       Applications of 'parse'  
  176.  
  177.     The 'CharsDemo' programs contains three examples of the use of the
  178.     powerful ARexx instruction 'parse', and some readers may be interested
  179.     in a closer look at them.
  180.  
  181.      1  Removing {labels} from a line of text
  182.     
  183.     If a line of {text} contains {labels} enclosed by {braces}, then those
  184.     labels can be extracted by using the '{' and the '}' alternately as
  185.     template markers, working along the line until it has all been parsed
  186.     out.  Within a loop : "do until txt = '' ..... end", the following line
  187.     does the work :
  188.  
  189.         parse var txt t1 '{' txt ; parse var txt t2 '}' txt
  190.  
  191.     First half
  192.     Take the part of the variable called 'txt' which lies before the
  193.     '{', assign it to 't1', and assign the remainder of 'txt' to another
  194.     variable also called 'txt', thereby overwriting the original.
  195.     
  196.     Second half
  197.     Do the same thing with the first part of the new 'txt', as far as the
  198.     '}', assigning it to 't2'.
  199.     
  200.     As we go through the loop, all contents of braces are thus isolated. 
  201.     In other coding not shown here a variable 'newtxt' is built up of the
  202.     pieces outside the braces, while the pieces inside the braces are
  203.     assigned to elements of the 'label. ' array.  The position of each
  204.     special character insertion is recorded in 'pos.n'.  It seems to work.
  205.     
  206.     
  207.      2  Finding each label in the data file
  208.     
  209.     When we are looking through the 'chars' file to find the line of data
  210.     relating to a particular shape, the first part of each line, as far as
  211.     its first comma, needs to be examined.  All lines are considered in
  212.     turn, the first element of each line being parsed out and compared with
  213.     the target label, until a match is found.  In (I hope) plain English :
  214.  
  215.        Do until 'found' is true, or the end of the file is reached.  
  216.          Read in the next line of the file.
  217.          Isolate the part of the line up to but not including a comma.
  218.          The rest of the line is called 'parms' for later use if required.
  219.          Compare the first part with the target label.
  220.          Set 'found' to TRUE if they match.
  221.     
  222.     In ARexx:  
  223.     
  224.          do until found | eof(cf)
  225.            t = readln(cf) ; parse var t lab ',' parms .
  226.            found = (lab = label.la)
  227.            end
  228.     
  229.  
  230.      3  Reading in the eight row values
  231.         
  232.     The eight row values for the found character definition are then
  233.     parsed out of the line.  You might expect this to be done in a loop,
  234.     like this :
  235.     
  236.          do pa = 1 to 8
  237.            parse var parms a.pa parms .
  238.            end
  239.     
  240.     But in fact I found that the following works slightly faster :
  241.     
  242.          parse var parms a.1 ',' a.2 ',' a.3 ',' a.4 ',' a.5 ',',
  243.                          a.6 ',' a.7 ',' a.8 .
  244.  
  245.      
  246.       Data conversion  
  247.     
  248.     In 'CharGrid' a constant record is kept of the state of all entries in
  249.     a set of compound variables of the form 'row.column.state' where
  250.     'row' and 'column' both range from 1 to 8 and 'state' is either 0 or 1.
  251.     (The actual stem and segment names in the program are more cryptic.)
  252.     The decimal values corresponding to each row are constantly updated and
  253.     displayed.  Given a row of entries the 'states' of which can be
  254.     represented thus: 01001011, it can be converted into a more
  255.     convenient form by :
  256.  
  257.          packed = 0
  258.          do col = 1 to 8
  259.           if row.column.state then packed = packed + 2**(8-column)
  260.           end
  261.     
  262.     This should yield 75 (reading 01001011 from right to left, 1 + 2 + 8 +
  263.     64).
  264.  
  265.     The reverse process is required when a set of eight decimal values is
  266.     read in from the data file in the 'load' option in 'CharGrid', and
  267.     when 'CharsDemo' obtains those values to display a character.  If the
  268.     array 'a.' is the set of decimal values, then the following patch
  269.     will convert them into sets of 0's and 1's (like converting the '75'
  270.     mentioned a few lines ago back into '01001011'.)
  271.  
  272.       do j = 1 to 8
  273.         if a.j = 0 then iterate  /* All zeros; no point going on */
  274.         octet = c2b(d2c(a.j))
  275.         do bit = 1 to 8
  276.     
  277.     If we actually want to draw a real-size character at position
  278.     col,row, we then use :
  279.     
  280.           if substr(octet,bit,1) then do
  281.             call Move(HO,col+bit,row); call Draw(HO,col+bit,row); end
  282.           end
  283.  
  284.     But if we are using the 'load' option to fill in the cells of the large
  285.     grid, then we need :
  286.  
  287.           if substr(octet,bit,1) then call DoCell(bit,j)
  288.           end
  289.         end
  290.     
  291.     See 'CharGrid' for details of the DoCell() function.
  292.     
  293.     Note how a single pixel is painted in. You call Move() to go to the
  294.     point in question, and then call Draw() with the same x and y
  295.     parameters. It just draws to where it is, and a single point is
  296.     produced.
  297.     
  298.     Also of interest is the assignment to 'octet'. Take the value '75', for
  299.     example, and see how it behaves in 'c2b(d2c(75))'.  If you want to
  300.     clarify the process, try these three stages in a CLI window : 
  301.  
  302.        rx 'say d2c(75)'      --> K
  303.        rx 'say c2b(K)'       --> 01001011
  304.        rx 'say c2b(d2c(75))' --> 01001011
  305.     
  306.     
  307.       What else could be done?  
  308.     
  309.     The demo includes one large character made up of two adjacent pieces,
  310.     giving a shape which is 16 pixels wide.  I have played around with
  311.     things like   _       _                           _
  312.                  |-  and  -|  with varying numbers of - in between,
  313.     and produced all sorts of gates and fences, with a lot more detail than
  314.     shown here.  You can also have characters vertically adjacent to
  315.     make towers, spires, or whatever.  In a wild few moments I designed
  316.     four quarters of a flower, arranged them together like this  /\
  317.     and then used Flood to give them some colour.                \/
  318.     There are all sorts of possibilities.
  319.     
  320.     If you want to be really adventurous, the grid in 'CharGrid' could be
  321.     made wider : 10, 12, 14, even 16 cells.  I tried it with 12, and it
  322.     worked, though rather slowly, and it did need a lot of adjustments 
  323.     to be made to the program - so much so that I dropped an earlier idea
  324.     of having grid size as an adjustable variable in the program.
  325.  
  326.  
  327.     Hamilton, N.Z.  September, 1991
  328.     
  329.                ------------------------------------
  330.     
  331.  
  332.     36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 -+- 36 
  333.  
  334.